package com.orkun.api.converter.core;

import java.util.HashMap;

import com.orkun.api.converter.impl.AddInfoConverter;
import com.orkun.api.converter.impl.AddressInfoModel;
import com.orkun.api.converter.reader.Reader;
import com.orkun.api.converter.writer.Writer;

/**
 * Singleton factory used for instantiating converters
 */
@SuppressWarnings("unchecked")
public enum ConverterFactory {
  INSTANCE;  //singleton

  // Reader and Writer registration
  private static HashMap<String, Writer<?>> registeredWriters = new HashMap<>();
  private static HashMap<String, Reader<?>> registeredReaders = new HashMap<>();
  
  public void registerWriter(String type, Writer<?> writer) {
    registeredWriters.put(type, writer);
  }

  public void registerReader(String type, Reader<?> reader) {
    registeredReaders.put(type, reader);
  }

  /**
   * Create a converter using
   * @param modelType an object to parse the data into
   * @param from input format (XML, CSV, ...etc)
   * @param to input format (XML, CSV, ...etc)
   * @return Converter instance
   */
  public <T extends AbsModel> Converter<T> createConverter(final Class<T> modelType, String from,
      String to) {

    if (modelType == AddressInfoModel.class) {
      try {
        return (Converter<T>) new AddInfoConverter(this.<AddressInfoModel>createReader(from),
            this.<AddressInfoModel>createWriter(to));
      } catch (Exception e) {
        System.out
            .println("ConverterFactory is called with an unregistrered file type in the FileTypes enum.");
        return null;
      }
    } else {
      String errMessage = "ConverterFactory is called with an unregistrered model type.";
      System.out.println(errMessage);
      return null;
    }
  }

  private <T extends AbsModel> Writer<T> createWriter(String to) throws Exception {
    Writer<T> writer = (Writer<T>) registeredWriters.get(to);
    if (writer != null)
      return writer;

    String name = Writer.class.getPackage().getName();
    writer = (Writer<T>) Class.forName(name + ".Writer" + to).newInstance();
    registeredWriters.put(to, writer);
    return writer;

  }

  private <T extends AbsModel> Reader<T> createReader(String from) throws Exception {
    Reader<T> reader = (Reader<T>) registeredReaders.get(from);
    if (reader != null)
      return reader;

    String name = Reader.class.getPackage().getName();
    reader = (Reader<T>) Class.forName(name + ".Reader" + from).newInstance();
    registeredReaders.put(from, reader);
    return reader;

  }
}
